package com.diu.infrastructure.persistent.repository;

import com.diu.domain.strategy.model.entity.StrategyAwardEntity;
import com.diu.domain.strategy.model.entity.StrategyEntity;
import com.diu.domain.strategy.model.entity.StrategyRuleEntity;
import com.diu.domain.strategy.model.vo.StrategyAwardRuleModelVO;
import com.diu.domain.strategy.repository.IStrategyRepository;
import com.diu.infrastructure.persistent.dao.IStrategyAwardDao;
import com.diu.infrastructure.persistent.dao.IStrategyDao;
import com.diu.infrastructure.persistent.dao.IStrategyRuleDao;
import com.diu.infrastructure.persistent.po.Strategy;
import com.diu.infrastructure.persistent.po.StrategyAward;
import com.diu.infrastructure.persistent.po.StrategyRule;
import com.diu.infrastructure.persistent.redis.IRedisService;
import com.diu.types.common.Constants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author diu
 * @description
 * @create_time 2025/10/3 17:22
 */
@Slf4j
@Repository
public class StrategyRepository implements IStrategyRepository {
    @Resource
    private IStrategyAwardDao strategyAwardDao;
    @Resource
    private IStrategyDao strategyDao;
    @Resource
    private IStrategyRuleDao strategyRuleDao;
    @Resource
    private IRedisService redisService;
    @Override
    public List<StrategyAwardEntity> queryStrategyAwardList(Long strategyId) {
        String cachedKey = Constants.RedisKey.STRATEGY_AWARD_KEY + strategyId;
        List<StrategyAwardEntity> strategyAwardEntities = redisService.getValue(cachedKey);
        if(strategyAwardEntities != null && !strategyAwardEntities.isEmpty()){
            log.info("从Redis缓存中查询策略奖品列表, strategyId: {}", strategyId);
            return strategyAwardEntities;
        }
        // 1.从数据库查询
        List<StrategyAward> strategyAwards = strategyAwardDao.queryStrategyAwardListByStrategyId(strategyId);
        List<StrategyAwardEntity> strategyAwardEntityList = new ArrayList<>(strategyAwards.size());
        if(strategyAwards != null && !strategyAwards.isEmpty()){
            for(StrategyAward strategyAward : strategyAwards){
                StrategyAwardEntity strategyAwardEntity = new StrategyAwardEntity().builder()
                        .strategyId(strategyId)
                        .awardId(strategyAward.getAwardId())
                        .awardCount(strategyAward.getAwardCount())
                        .awardCountSurplus(strategyAward.getAwardCountSurplus())
                        .awardRate(strategyAward.getAwardRate())
                        .build();
                strategyAwardEntityList.add(strategyAwardEntity);
            }
            redisService.setValue(cachedKey, strategyAwardEntityList);
        }
        return strategyAwardEntityList;
    }

    @Override
    public StrategyEntity queryStrategyByStrategyId(Long strategyId) {
        String cachedKey = Constants.RedisKey.STRATEGY_KEY + strategyId;
        StrategyEntity strategyEntity = redisService.getValue(cachedKey);
        if(strategyEntity != null){
            log.info("从Redis缓存中查询策略, strategyId: {}", strategyId);
            return strategyEntity;
        }
        // 1.从数据库查询
        Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId);
        if(strategy == null){
            return null;
        }
        strategyEntity = new StrategyEntity().builder()
                .strategyId(strategy.getStrategyId())
                .strategyDesc(strategy.getStrategyDesc())
                .ruleModels(strategy.getRuleModels())
                .build();
        redisService.setValue(cachedKey, strategyEntity);
        return strategyEntity;
    }

    @Override
    public StrategyRuleEntity queryStrategyRuleByStrategyId(Long strategyId){
        String cachedKey = Constants.RedisKey.STRATEGY_RULE_KEY + strategyId;
        StrategyRuleEntity strategyRuleEntity = redisService.getValue(cachedKey);
        if(strategyRuleEntity != null){
            log.info("从Redis缓存中查询策略规则, strategyId: {}", strategyId);
            return strategyRuleEntity;
        }
        StrategyRule strategyRule = strategyRuleDao.queryStrategyRuleByStrategyId(strategyId);
        if(strategyRule == null){
            return null;
        }
        StrategyRuleEntity strategyRuleEntityTemp = new StrategyRuleEntity().builder()
                    .strategyId(strategyId)
                    .ruleModel(strategyRule.getRuleModel())
                    .ruleValue(strategyRule.getRuleValue())
                    .build();
        redisService.setValue(cachedKey, strategyRuleEntity);
        return strategyRuleEntity;
    }

    @Override
    public StrategyRuleEntity queryStrategyRuleByStrategyIdAndRuleModel(Long strategyId, String ruleModel) {
        String cachedKey = Constants.RedisKey.STRATEGY_RULE_KEY + strategyId + "_" + ruleModel;
        StrategyRuleEntity strategyRuleEntity = redisService.getValue(cachedKey);
        if(strategyRuleEntity != null){
            log.info("从Redis缓存中查询策略规则, strategyId: {}, ruleModel: {}", strategyId, ruleModel);
            return strategyRuleEntity;
        }
        StrategyRule strategyRule = strategyRuleDao.queryStrategyRuleByStrategyIdAndRuleModel(strategyId, ruleModel);
        strategyRuleEntity = new StrategyRuleEntity().builder()
                .strategyId(strategyId)
                .ruleModel(strategyRule.getRuleModel())
                .ruleValue(strategyRule.getRuleValue())
                .build();
        if(strategyRule != null){
            redisService.setValue(cachedKey, strategyRuleEntity);
        }
        return strategyRuleEntity;
    }

    @Override
    public StrategyAwardEntity queryStrategyAwardListByStrategyAndAwardId(Long strategyId, Integer awardId) {
        // 1.从数据库查询
        StrategyAward strategyAward = strategyAwardDao.queryStrategyAwardListByStrategyAndAwardId(strategyId, awardId);
        if(strategyAward == null){
            return null;
        }
        StrategyAwardEntity strategyAwardEntity = new StrategyAwardEntity().builder()
                .strategyId(strategyId)
                .awardId(strategyAward.getAwardId())
                .awardCount(strategyAward.getAwardCount())
                .awardCountSurplus(strategyAward.getAwardCountSurplus())
                .awardRate(strategyAward.getAwardRate())
                .build();
        return strategyAwardEntity;
    }

    @Override
    public String queryStrategyRuleValue(Long strategyId, Integer awardId, String ruleModel) {
        StrategyRule strategyRule = strategyRuleDao.queryStrategyRuleByStrategyIdAndAwardIdAndRuleModel(strategyId, awardId, ruleModel);
        if(strategyRule == null){
            return null;
        }
        return strategyRule.getRuleValue();
    }

    @Override
    public StrategyEntity queryStrategyEntityByStrategyId(Long strategyId) {
        Strategy strategy = strategyDao.queryStrategyByStrategyId(strategyId);
        return StrategyEntity.builder()
                .strategyId(strategy.getStrategyId())
                .strategyDesc(strategy.getStrategyDesc())
                .ruleModels(strategy.getRuleModels())
                .build();
    }

    @Override
    public StrategyAwardRuleModelVO queryStrategyAwardRuleModel(Long strategyId, Integer awardId){
        StrategyAward strategyAward = strategyAwardDao.queryStrategyAwardListByStrategyAndAwardId(strategyId, awardId);
        if(strategyAward == null){
            return null;
        }
        return StrategyAwardRuleModelVO.builder()
                .ruleModels(strategyAward.getRuleModels())
                .build();
    }

    @Override
    public void storeStrategyAwardSearchRateTable(String key, Integer strategyAwardSearchTableSize, Map<Integer, Integer> strategyAwardSearchTable) {
        redisService.setValue(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key, strategyAwardSearchTable);
        redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, strategyAwardSearchTableSize);
    }

    @Override
    public void storeStrategyAwardSearchRateTableOwn(String key, Integer strategyAwardSearchTableSize, Map<BigDecimal, Integer> strategyAwardSearchTable, BigDecimal totalRate) {
        redisService.setValue(Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key, strategyAwardSearchTable);
        redisService.setValue(Constants.RedisKey.STRATEGY_RATE_RANGE_KEY + key, strategyAwardSearchTableSize);
        redisService.setValue(Constants.RedisKey.STRATEGY_TOTAL_RATE_KEY + key, totalRate);
    }

     @Override
    public BigDecimal getRateRange(String key) {
        String cachedKey = Constants.RedisKey.STRATEGY_TOTAL_RATE_KEY + key;
        BigDecimal totalRate = redisService.getValue(cachedKey);
        if(totalRate == null){
            return BigDecimal.ZERO;
        }
        return totalRate;
    }

    @Override
     public Integer getStrategyAwardAssemble(Long strategyId, int rateRange) {
        String cachedKey = Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + strategyId;
        Map<Integer, Integer> rateRangeMap = redisService.getValue(cachedKey);
        if(rateRangeMap == null || rateRangeMap.isEmpty()){
            return null;
        }
        return rateRangeMap.get(rateRange);
     }

     @Override
     public Integer getStrategyAwardAssembleOwn(String key, BigDecimal rateRange) {
        String cachedKey = Constants.RedisKey.STRATEGY_RATE_TABLE_KEY + key;
        // jackson 反序列化时，会将Map集合的 key 转换为字符串
        Map<String, Integer> rateRangeMap = redisService.getValue(cachedKey);
        if(rateRangeMap == null || rateRangeMap.isEmpty()){
            return null;
        }
         rateRangeMap = rateRangeMap.entrySet().stream()
                 .sorted((e1, e2) -> {
                     BigDecimal bd1 = new BigDecimal(e1.getKey());
                     BigDecimal bd2 = new BigDecimal(e2.getKey());
                     return bd1.compareTo(bd2); // 升序
                 }).collect(Collectors.toMap(
                         e -> e.getKey(),
                         e -> e.getValue(),
                         (v1, v2) -> v1,
                         LinkedHashMap::new));
        for(Map.Entry<String, Integer> entry : rateRangeMap.entrySet()){
            if(new BigDecimal(entry.getKey()).compareTo(rateRange) >= 0){
                return entry.getValue();
            }
        }
        return null;
     }

}
